-module(subscriber_sup).
-behaviour(supervisor).
-export([init/1]).
-export([start_link/0]).
-export([create/2,create/3,associate/3,list_sub/0]).

-define(SERVER,?MODULE).


start_link() ->
	supervisor:start_link({local,?SERVER},?MODULE,[]).

init([]) ->
	Children = [
		{subscriber_gen,{gen_server,start_link,[]},temporary,brutal_kill,worker,[gen_server,subscriber_lte]}
		],
	RestartStrategy = {simple_one_for_one,0,1},
	{ok,{RestartStrategy,Children}}.



start_child(Sub_Type,Status) -> %% create a subscriber process
	try
		{ok,Pid} = supervisor:start_child(?SERVER,[Sub_Type,[Status],[]]),
		Pid
	catch
		{badmatch,V} ->
			throw(sub_create_failure)
	end.
associate(Key,Pid,Options) ->
	Sub_Pid = dict_check(Key),
	case {Sub_Pid,mode(Options)} of
	{unknown,_} ->
		dict_add(Key,Pid),
		{ok,Pid};
	{_,force} -> %% find and force existing terminate
		update(Sub_Pid,terminate),
		dict_erase(Key),
		dict_add(Key,Pid),
		{ok,Pid};
	{Pid,_} ->		%% duplicate register
		{ok,Pid};
	_ ->
		{error,association_exists}
	end.
create(Status,Options) ->
	try
		Pid = start_child(subscriber_type(Options),Status),
		Pid
	catch
		sub_create_failure ->
			{error,create_failure}
	end.

create(Key,Status,Options) ->	%% create a subscriber process and register it.
	Sub_Pid = dict_check(Key),
	try
		case {Sub_Pid,mode(Options)} of
		{unknown,_} ->
			Pid = create(Status,Options),
			dict_add(Key,Pid),
			{ok,Pid};
		{Pid,force} -> %% find and force existing terminate
			update(Pid,terminate),
			dict_erase(Key),
			NewPid = create(Status,Options),
			dict_add(Key,NewPid),
			{ok,NewPid};
		{Pid,associate} ->
			{ok,Pid};
		{Pid,detect} -> %% if existing , return error
			{error,Pid}
		end
	catch
		sub_create_failure ->
			{error,create_failure}
	end.

get_dict_server(tmsi) ->
	tmsi_dict;
get_dict_server(imsi) ->
	tmsi_dict;
get_dict_server(guti) ->
	tmsi_dict.

dict_add({Id_Type,Id},Pid) ->
	gen_server:call(get_dict_server(Id_Type),{add,{Id,Pid}}).
dict_check({Id_Type,Id}) ->
	gen_server:call(get_dict_server(Id_Type),{get,Id}).
dict_erase({Id_Type,Id}) ->
	gen_server:call(get_dict_server(Id_Type),{erase,Id}).

subscriber_type([subscriber_lte|Options]) ->
	subscriber_lte;
subscriber_type([_|Options]) ->
	subscriber_type(Options);
subscriber_type([]) ->
	subscriber_lte.

mode([force|Options]) ->
	force;
mode([associate|Options]) ->
	associate;
mode([detect|Options]) ->
	detect;
mode([_|Options]) ->
	mode(Options);
mode([]) ->
	false.
update(Pid,Message) ->
	gen_server:call(Pid,Message).

list_sub() ->
	try
		lists:map(
				fun({_Id,Child,_Type,_Modules}) ->
					{ok,State} = gen_server:call(Child,dump),
					State
				end,
				(supervisor:which_children(?SERVER)))
	catch
		error:Reason ->
				"error"
	end.
